﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Brainee.Search
{
  /// <summary>
  /// A generic iterative algorithm that can be used to solve problems.
  /// </summary>
  public class RecursiveSearch : ISearchAlgorithm
  {
#region Properties

    /// <summary>
    /// Maximum depth of the iterative algorithm
    /// </summary>
    public UInt32 Limit { get; set; }

#endregion
#region Events

    /// <summary>
    /// An event that is raised whenever a solution is found.
    /// </summary>
    //public event EventHandler<SolutionFoundEventArg> SolutionFound;

#endregion
#region Solve problem

    /// <summary>
    /// Solve the specified problem.
    /// </summary>
    /// <param name="problem">The problem to solve</param>
    /// <returns>The solution of the problem if it exists. Otherwise, PathSolution.None.</returns>
    public PathSolution Solve (IProblem problem)
    {
      if (problem == null)
        throw new ArgumentNullException ("problem");

      // Start recursion
      return Recurse (new SearchState (problem.InitialState), problem);
    }

    private PathSolution Recurse (SearchState state, IProblem problem)
    {
      bool cutoff = false;

      if (problem.GoalTest (state.State))
      {
        // A solution has been found
        PathSolution sol = new PathSolution (state);
        return sol;

        //// If no handler has been registered, return this solution
        //if (SolutionFound == null)
        //  return sol;

        //// Raise the SolutionFound event and check if we should stop here.
        //SolutionFoundEventArg e = new SolutionFoundEventArg (sol);
        //SolutionFound (this, e);
        //if (e.Continue == false)
        //  return sol;
      }

      if (state.Depth == Limit)
        return PathSolution.Cutoff;

      foreach (ActionState pair in problem.Successors (state.State))
      {
        SearchState next = new SearchState (
                    pair.State,
                    state,
                    pair.Action,
                    state.PathCost + problem.StepCost (state.State, pair.Action, pair.State),
                    state.Depth + 1);

        PathSolution solution = Recurse (next, problem);

        if (solution == PathSolution.Cutoff)
          cutoff = true;

        else if (solution != PathSolution.None)
          return solution;
      }

      if (cutoff)
        return PathSolution.Cutoff;
      else
        return PathSolution.None;
    }

#endregion
  }
}
